/**
 * Class: Tree
 *
 * Purpose: 
 *
 * Created: Jan 29, 2010 @ 1:51:54 PM
 * @author Ken Scott
 */
package org.openfantasia.ps.tree;

import org.openfantasia.ps.Space;
import org.openfantasia.ps.particle.Particle;
import org.openfantasia.ps.actor.Actor;
import org.openfantasia.ui.PColor;
import org.openfantasia.util.math.DPoint3;
import org.openfantasia.util.math.PMath;

import java.util.ArrayList;
import java.util.List;

public class Tree extends Particle {

	protected Tree parent;

	protected List<Tree> branches;

	protected List<Leaf> leaves;

	protected Actor branchActor;

	protected Actor leafActor;


	public Tree(Actor branchActor, Actor leafActor, int depth, Tree parent, DPoint3 base, DPoint3 angle, long seed, int minBranches, int maxBranches, double minAngle, double maxAngle, double minGrowth, double maxGrowth, double length) {
		setForceSensitive(false);
		setFillColor(PColor.GRAY.darker());
		
		this.parent = parent;
		this.actor = branchActor;

		int subCount = PMath.random(minBranches, maxBranches);
		if (depth > 0) {
			depth--;
			branches = new ArrayList<Tree>();
			DPoint3 newBase = base.copy().add(angle.copy().scale(length));
			position = newBase;
			previousPosition = base.copy();
			for (int branchIdx = 0; branchIdx < subCount; branchIdx++) {
				DPoint3 newAngle = angle.copy().addNoise(PMath.random(minAngle, maxAngle)).normalize();
				double newLength = length * PMath.random(minGrowth, maxGrowth);
				Tree branch = new Tree(branchActor, leafActor, depth, this, newBase, newAngle, seed + 1, minBranches, maxBranches, minAngle, maxAngle, minGrowth, maxGrowth, newLength);
				branches.add(branch);
			}
		}
		else {
			leaves = new ArrayList<Leaf>();
			for (int leafIdx = 0; leafIdx < subCount; leafIdx++) {
				Leaf leaf = new Leaf();
				leaf.setActor(leafActor);
				leaf.setPosition(base.copy());
				leaves.add(leaf);
			}
		}
	}


	public void setSpace(Space space) {
		this.space = space;
		if(hasBranches()) {
			for(Tree branch : branches) {
				space.addParticle(branch);
			}
		}

		if(hasLeaves()) {
			for(Leaf leaf : leaves) {
				space.addParticle(leaf);
			}
		}
	}


	public void setActors(Actor branchR, Actor leafR) {
		setActor(branchR);
		
		if(hasBranches()) {
			for(Tree branch : branches) {
				branch.setActors(branchR, leafR);
			}
		}

		if(hasLeaves()) {
			for(Leaf leaf : leaves) {
				leaf.setActor(leafR);
			}
		}
	}


	public boolean hasBranches() {
		return (branches != null) && !branches.isEmpty();
	}


	public boolean hasLeaves() {
		return (leaves != null) && !leaves.isEmpty();
	}


	public Tree getParent() {
		return parent;
	}


	public List<Tree> getBranches() {
		return branches;
	}


	public List<Leaf> getLeaves() {
		return leaves;
	}
}
